'''
Converts parsed data from Parser.decodeReplay into feature vectors
Authors:
    Shengling Hu

Usage:
    From containing directory
    python parser.py

    or

    python parser.py -g 111280
'''
import pickle
from pprint import pprint
import os
from math import sqrt

REPLAY_PREFIX = os.path.join('..', '..', 'data', 'replays')
FEATURE_PREFIX = os.path.join('..', '..', 'data', 'features')
if (not os.path.isdir(REPLAY_PREFIX)):
    os.mkdir(REPLAY_PREFIX)
if (not os.path.isdir(FEATURE_PREFIX)):
    os.mkdir(FEATURE_PREFIX)
DEFAULT_GAME_NO = '115671'
DEFAULT_REPLAY = os.path.join(REPLAY_PREFIX, DEFAULT_GAME_NO)
DEFAULT_FEATURE = os.path.join(FEATURE_PREFIX, DEFAULT_GAME_NO)
MAXROW = 128
MAXCOL = 112

def extractFeature(replay_file,functions):
    '''
    Extracts list of features( where function maps replay_file to
        a feature vector, which may be part of a larger feature vector
    functions is a list of function that takes a player's data and creates a vector
    replay_file is the file containing the pickled player data

    Outputs list of features for each player in the format:
    [[player_num1,[functions[0] output with replay files]...],
     [player_num2,...]

    '''
    #Using 2 args right now, considering tupling right now
    a = pickle.load(replay_file)
    (hills,states) = a
    features = []
    for i,hill in enumerate(hills):
        features.append([i])
        for f in functions:
            l = len(states[i])
            for turns in range(0,l,5):
                v = []
                for j in range(0,min(l-turns,5)):
                    turn = turns + j
                    v.append(f(hill,states[i][turn]))
                s = []
                for pos in range(0,len(v[0])):
                    vals = [v[n][pos] for n in range(len(v))]
                    s.append(sum(vals)/len(vals))
                features[i].append(s)

    return features

def getRegions(hill,state):
    '''
    Uses region_map, which takes (hill,location) and maps it to a integer index.
    Returns a feature vector that can be concatenated to a big one

    '''
    region_map = mapSquaredly
    #unhardcode this at some point to match the thing in map function
    results = [0 for i in range(100)]
    for loc in state:
        results[region_map(hill,loc)] += 1
    return results


def mapRadially(hill,location):
    '''
    Returns i if less than radii[i]... otherwise

    '''

    maxDis = (MAXROW**2 + MAXCOL**2)**.5
    #range generation if decide to not hardcode, to be finished
    radii = [5, 10, 30, 50]
    y = abs(hill[0]-location[0])%MAXROW
    x = abs(hill[1]-location[1])%MAXCOL
    y = min(y,MAXROW-y)
    x = min(x,MAXCOL-x)
    d = (x**2 + y**2)**.5
    for n,r in enumerate(radii):
        if d < r:
            return n

    return len(radii)

def mapSquaredly(hill,location):
    """
        Map the locationss by of squares of rectangles indicated at the top of
        this function

    """
    nR = 10
    nC = 10
    y0 = hill[0]-MAXROW/2
    x0 = hill[1]-MAXCOL/2
    #range generation if decide to not hardcode, to be finished
    y_rel = abs(hill[0]-y0)%MAXROW
    x_rel = abs(hill[1]-x0)%MAXCOL
    r = y_rel//nR
    c = x_rel//nC
    return r*nC + c


def get_neighbors(loc, max_dist):
    """
        ADAPTED FROM ANTS TOOLS FROM AI CHALLENGE
        Return a list of squares within a given distance of loc

        Loc is not included in the list
        For all squares returned: 0 < distance(loc,square) <= max_dist

        Offsets are calculated so that:
          -height <= row+offset_row < height (and similarly for col)
          negative indicies on self.map wrap thanks to python
    """
    offsets = []
    mx = max_dist
    msq = max_dist**2;
    for d_row in range(-mx,mx+1):
        for d_col in range(-mx,mx+1):
            d = d_row**2 + d_col**2
            if 0 < d <= msq:
                offsets.append((
                    (d_row+loc[0])%MAXROW,
                    (d_col+loc[1])%MAXROW
                ))
    return offsets

def get_vision_matix(locs,radius):

    visible = [[false for i in range(MAX_COL)] for i in range(MAX_ROW)]
    for ant in locs:
        for (r,c) in get_neighbors(ant,radius):
            visible[r][c] = true

    return visible

def get_visible(vision, their_ants):
    """
        Returns the list of elements in locs that is visible in vision

    """
    visible = []
    for (r,c) in their_ants:
        if vision[r][c]:
            visible.append((r,c))

    return visible

if __name__ == '__main__':
    """
    games = [115671, 116944, 117034, 117067, 117297, 149452, 149357, 149342, 149316, 149186, 149166, 147481]
    for game in games:
        print('Extracting features for game ' + str(game) + '\n')
        in_file=open(os.path.join(REPLAY_PREFIX,str(game)),'r')
        all_features = extractFeature(in_file,[getRegions])
        for pfea in all_features:
            out_file = open(os.path.join(FEATURE_PREFIX,str(game)) + "_" + str(pfea[0]),'wb')
            pickle.dump(pfea[1:], out_file)
            out_file.close()
        print('Done with ' +  str(game) + '\n')
        in_file.close()
    """
    a = neighbourhood_offsets((20,20),5)
    pprint(a)
